package cn.xzzz2020.XJynWeb.aop;

import cn.xzzz2020.XJynWeb.aop.aspect.AspectInfo;
import cn.xzzz2020.XJynWeb.utils.ValidationUtil;
import lombok.Getter;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

/**
 * @author xzzz2020
 * @version 1.0
 * @date 2020/8/5 11:15
 */
public class AspectListExecutor implements MethodInterceptor {
    //被代理的类
    private Class<?> targetClass;
    //排过序的Aspect列表
    @Getter
    private List<AspectInfo> sortedAspectInfos;

    public AspectListExecutor(Class<?> targetClass, List<AspectInfo> aspectInfos) {
        this.targetClass = targetClass;
        this.sortedAspectInfos = sortAspectInfoList(aspectInfos);
    }

    /**
     * 根据aspectInfos的Order属性值进行排序
     *
     * @param aspectInfos
     * @return
     */
    private List<AspectInfo> sortAspectInfoList(List<AspectInfo> aspectInfos) {
        aspectInfos.sort(new Comparator<AspectInfo>() {
            @Override
            public int compare(AspectInfo o1, AspectInfo o2) {
                //按照order的大小排序
                return o1.getOrderIndex() - o2.getOrderIndex();
            }
        });
        return aspectInfos;
    }

    /**
     * 实现被代理类的织入逻辑
     * @param proxy
     * @param method
     * @param args
     * @param methodProxy
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object returnValue = null;
        //对代理类进行精筛
        collectAccurateMatchedAspectList(method);
        if (ValidationUtil.isEmpty(sortedAspectInfos)){
            return methodProxy.invokeSuper(proxy,args);
        }
        try {
            //1.按照order的顺序升序执行完所有Aspect的before方法
            invokeBeforeAdvices(method,args);
            //2.执行被代理类的方法
            returnValue = methodProxy.invokeSuper(proxy,args);
            //3.如果被代理方法正常返回，则按照order的顺序降序执行完所有Aspect的afterReturning方法
            returnValue = invokeAfterReturningAdvice(method,args,returnValue);
        } catch (Throwable throwable) {
            //4.如果被代理方法抛出异常，则按照order的顺序降序执行完所有Aspect的afterThrowing方法
            invokeAfterThrowingAdvices(method,args,throwable);
        }
        return returnValue;
    }

    /**
     * 对代理类进行精筛
     * @param method
     */
    private void collectAccurateMatchedAspectList(Method method) {
        if (!ValidationUtil.isEmpty(sortedAspectInfos)){
            Iterator<AspectInfo> iterator = sortedAspectInfos.iterator();
            while (iterator.hasNext()){
                AspectInfo aspectInfo = iterator.next();
                if (!aspectInfo.getPointcutLocator().accurateMatches(method)){
                    iterator.remove();
                }
            }
        }
    }

    //如果被代理方法抛出异常，则按照order的顺序降序执行完所有Aspect的afterThrowing方法
    private void invokeAfterThrowingAdvices(Method method, Object[] args, Throwable throwable) throws Throwable {
        for(int i = sortedAspectInfos.size()-1;i>=0;i--){
           sortedAspectInfos.get(i).getDefaultAspect().afterThrowing(targetClass,method,args,throwable);
        }
    }

    //如果被代理方法正常返回，则按照order的顺序降序执行完所有Aspect的afterReturning方法
    private Object invokeAfterReturningAdvice(Method method, Object[] args, Object returnValue) throws Throwable {
        Object result = null;
        for(int i = sortedAspectInfos.size()-1;i>=0;i--){
            result = sortedAspectInfos.get(i).getDefaultAspect().afterReturning(targetClass,method,args,returnValue);
        }
        return result;
    }

    //按照order的顺序升序执行完所有Aspect的before方法
    private void invokeBeforeAdvices(Method method, Object[] args) throws Throwable {
        for (AspectInfo sortedAspectInfo : sortedAspectInfos) {
            sortedAspectInfo.getDefaultAspect().before(targetClass,method,args);
        }
    }
}
